#include "StepByStep.h"

#define MINIEFFECT
#define NEWMOTHED

#ifdef NEWMOTHED
#define MULTIPCS
#endif

#ifdef NEWMOTHED
#define DELETE_STATIC_CPC1
#endif

PredKnowledge* CopyOnePCOfAction(TypedList *Para, PENode *PE)
{
  PredKnowledge *Pd;
  TokenList     *Pt1;
  TypedList     *P2;
  int           j, Num;

  Pd = (PredKnowledge *) calloc(1, sizeof(PredKnowledge));

  Pd->Fact = TRUE;
  Pd->Type = PE->Type;

  Pt1 = PE->Pred;
  Pd->PredNo = Pt1->VList.ParaIdx;

  Num = NumParaOfPred(Pd->PredNo);

  if (Num == 0) return Pd;

  Pd->NumNonValue = Num;
  Pd->Para = P2 = (TypedList *) calloc(Num, sizeof(TypedList));

  for (Pt1 = Pt1->next; Pt1 != NULL; P2++,Pt1=Pt1->next) {
    P2->VList.ParaIdx = j = Pt1->VList.ParaIdx;
    if (!IsConstant(j)) {
       strcpy(P2->VList.Name, (Para+j)->VList.Name);
       P2->Type = CopyListOfType((Para+j)->Type);

       if (!IsExtraPara((Para+j)->VList.ParaIdx)) Pd->NumNonValue--;
    }
    else {
           P2->Type = (StringList *) calloc(1, sizeof(StringList));
           strcpy(P2->Type->Name, CONST_TYPE);

           Pd->NumNonValue--;
           InsertOneValueIntoValueList(j, &(P2->VList));
    }
  }

  return Pd;
}

PredKnowledge* PCInAction(int *Para1, PredKnowledge *PC, ParaOfAct *APara, ActKnowledge *ActK2)
{
  PredKnowledge *PC1;
  TypedList     *Pt1, *Pt2;
  Bool          Equal;
  int           i, idx1, idx2, Num, NumPC, *Pt, *Pt3;

  Num = APara->Num;
  NumPC = NumParaOfPred(PC->PredNo);
  for (PC1 = ActK2->PC; PC1 != NULL; PC1 = PC1->next) {
    if (PC->Type!=PC1->Type || PC->PredNo!=PC1->PredNo) continue;

    Equal = TRUE;
    Pt1 = PC->Para;   Pt2 = PC1->Para;
    for (i = 0; Equal && i<NumPC; i++,Pt1++,Pt2++) {
      idx1 = Pt1->VList.ParaIdx;
      idx2 = Pt2->VList.ParaIdx;

      if (IsConstant(idx1) || IsConstant(idx2)) Equal = (idx1 == idx2);
      else {
             Pt = APara->Para + idx2;
             Pt3 = Para1 + idx1;

             if (*Pt != NOFOUND) Equal = (*Pt==*Pt3);
             else if (!CheckTransform(Num, APara->Para, idx2, *Pt3)) return FALSE;
      }
    }

    if (Equal) return PC1;
  }

  return NULL;
}

PENode* CopyEffectOfAction(PENode *PE)
{
  PENode *PE1, *PE2, *PE3;

  PE1 = PE2 = NULL;
  for (; PE != NULL; PE = PE->next) {
    PE3 = (PENode *) calloc(1, sizeof(PENode));
    PE3->Type = PE->Type;
    PE3->Delete = PE->Delete;
    PE3->Pred = CopyTokenList(PE->Pred);

    if (PE2 == NULL) PE1 = PE3;
    else PE2->next = PE3;

    PE2 = PE3;
  }

  return PE1;
}

#ifdef WHEN_CLAUSE
PENode *CopyWhenClause(PENode *PE)
{
  PENode *PE1;

  PE1 = (PENode *) calloc(1, sizeof(PENode));
  PE1->Type = PE->Type;

  PE1->sons = CopyEffectOfAction(PE->sons);
  PE1->Effect = CopyEffectOfAction(PE->Effect);

  return PE1;
}

void CopyCondEffectOfAction(ActKnowledge *ActK, PENode *PE, int Index)
{
  PredKnowledge *PC, *PC1;
  PENode        *PE1, *PE2, *PE3, *PE4;
  int           Idx;

  ActK->CondEffect = NULL;
  for (Idx = 0; PE != NULL; Idx++,PE=PE->next) {
    if (Idx != Index) {
       PE2 = CopyWhenClause(PE);

       if (ActK->CondEffect == NULL) ActK->CondEffect = PE2;
       else PE1->next = PE2;

       PE1 = PE2;
       continue;
    }

    PC1 = NULL;
    for (PC = ActK->PC; PC != NULL; PC = PC->next) PC1 = PC;

    // Insert PC Of When into PC of ActK
    for (PE3 = PE->sons; PE3 != NULL; PE3 = PE3->next) {
      PC = CopyOnePCOfAction(ActK->Para, PE3);
      PC->Level = 2;
      PC->Parent = ActK->Parent;

      if (PC1 == NULL) ActK->PC = PC;
      else PC1->next = PC;

      PC1 = PC;
    }

    PE4 = NULL;
    for (PE3 = ActK->Effect; PE3 != NULL; PE3 = PE3->next) PE4 = PE3;

    // insert Effect List Of When into Effect of ActK
    for (PE3 = PE->Effect; PE3 != NULL; PE3 = PE3->next) {
      PE2 = (PENode *) calloc(1, sizeof(PENode));
      PE2->Type = PE3->Type;
      PE2->Pred = CopyTokenList(PE3->Pred);

      if (PE4 == NULL) ActK->Effect = PE2;
      else PE4->next = PE2;

      PE4 = PE2;
    }
  }
}
#endif

Bool EqualNoPredAndPC(PredKnowledge *Pd, TypedList *Para, PredKnowledge *PC)
{
  TypedList *Pt1, *Pt2;
  Bool      Ok;
  int       i, idx, Num;

  Ok = (PC->Type!=Pd->Type && PC->PredNo==Pd->PredNo);

  Num = NumParaOfPred(Pd->PredNo);
  Pt1 = PC->Para;  Pt2 = Pd->Para;
  for (i = 0; Ok && i<Num; i++,Pt1++,Pt2++) {
    idx = Pt1->VList.ParaIdx;
    if (!IsConstant(idx)) {
       idx = (Para+idx)->VList.ParaIdx;
       if (!IsExtraPara(idx)) idx = (Pd->Para+idx)->VList.ParaIdx;
    }
    Ok = (idx==Pt2->VList.ParaIdx);
  }

  return Ok;
}

#ifdef MINIEFFECT
// Delete Action in the tree for Minimum Effect
void DeleteActionWithMinimumEffect(PredKnowledge *Pd)
{
  PredKnowledge *PC;
  ActKnowledge  *ActK, *ActK1, *ActK2;
  PENode        *PE;
  int           Num1, Num2, NumCPC, NumCEffect;

  NumCPC = 0;
  for (PC = Pd->CPC; PC != NULL; PC = PC->next)
    if (!IsEqual(PC->PredNo)) NumCPC++;

  if (Pd->Type == NOT) NumCPC++;

  NumCEffect = 1;
  for (PE = Pd->CEffect; PE != NULL; PE = PE->next) NumCEffect++;

  for (ActK = Pd->Act; ActK != NULL; ActK = ActK->next) {
    Num1 = 0;
    for (PC = ActK->PC; PC != NULL; PC = PC->next)
      if (!IsEqual(PC->PredNo)) Num1++;

    Num2 = 0;     // Get Number Of Effect
    for (PE = ActK->Effect; PE != NULL; PE = PE->next) Num2++;

    if (Num1==NumCPC && Num2==NumCEffect) break;
  }

  if (ActK == NULL) return;

  for (ActK1 = Pd->Act; ActK1 != NULL; ActK1 = ActK2) {
    ActK2 = ActK1->next;
    if (ActK1 != ActK) FreeActKnowledge(ActK1);
  }

  Pd->NumAct = 1;  Pd->Act = ActK;  ActK->next = NULL;
}
#endif

void ChangeInfoOfKTreeByCEffect(PENode *PE, ParaOfAct *APara, PredKnowledge *Pd)
{
  ActKnowledge *ActK, *ActK1;
  TypedList    *Pt1, *Pt2;
  TokenList    *Pt3;
  int          j, i1, j1, AllNum;

  AllNum = NumParaOfPred(Pd->PredNo) + Pd->NumEP;

  ActK = Pd->Act;
  for (Pt3 = PE->Pred->next; Pt3 != NULL; Pt3 = Pt3->next) {
    j = Pt3->VList.ParaIdx;
    if (IsConstant(j)) continue;

    if (!IsExtraPara(APara[0].Para[j])) {
       Pt3->VList.ParaIdx = APara[0].Para[j];
       continue;
    }

    for (i1=1,ActK1=ActK->next; ActK1 != NULL; i1++,ActK1=ActK1->next) {
      Pt1 = ActK1->Para;
      for (j1 = 0; j1 < APara[i1].Num; j1++,Pt1++)
        if (APara[i1].Para[j1]==APara[0].Para[j]) Pt1->VList.ParaIdx = AllNum;
    }

    Pt1 = ActK->Para + j;

    Pt1->VList.ParaIdx = APara[0].Para[j] = AllNum;
    Pt3->VList.ParaIdx = AllNum++;

    Pd->NumEP++;
    Pd->Para = (TypedList *) realloc(Pd->Para, (AllNum)*sizeof(TypedList));

    Pt2 = Pd->Para + (AllNum-1);

    Pt2->VList.ParaIdx = AllNum-1;
    strcpy(Pt2->VList.Name, Pt1->VList.Name);
    Pt2->Type = CopyListOfType(Pt1->Type);
    Pt2->VList.List = NULL;
    CopyValueList(&(Pt2->VList), &(Pt1->VList));
  }
}

Bool EqualEffects(int *Para, PENode *PE1, int *Para2, PENode *PE2)
{
  TokenList *Pt1, *Pt2;
  int       j, k;

  if (PE1->Type != PE2->Type || PE1->Pred->VList.ParaIdx != PE2->Pred->VList.ParaIdx)
     return FALSE;

  Pt1 = PE1->Pred->next;   Pt2 = PE2->Pred->next;
  while (Pt1 != NULL) {
    j = Pt1->VList.ParaIdx;
    k = Pt2->VList.ParaIdx;

    if (!IsConstant(j)) j = Para[j];
    if (!IsConstant(k)) k = Para2[k];

    if (k != j) break;

    Pt1 = Pt1->next;  Pt2 = Pt2->next;
  }

  return (Pt1 == NULL);
}

Bool CheckOneEffect(ParaOfAct *APara, PENode *PE, ActKnowledge *ActK)
{
  ActKnowledge *ActK1;
  PENode       *PE1, *PE2;
  int          j, k;

  for (j=1,ActK1=ActK; ActK1 != NULL; j++,ActK1=ActK1->next) {
    for (k=0,PE1=ActK1->Effect; PE1 != NULL; k++,PE1=PE1->next)
      if (EqualEffects(APara[0].Para, PE, APara[j].Para, PE1)) {
         APara[j].Idx = k;
         break;
      }

    if (PE1 == NULL) break;
  }

  if (ActK1 != NULL) return FALSE;

  for (j=1,ActK1=ActK; ActK1 != NULL; j++,ActK1=ActK1->next) {
    PE2 = NULL;
    PE1 = ActK1->Effect;
    for (k = 0; k < APara[j].Idx; k++) PE2=PE1,PE1=PE1->next;

    if (PE2 == NULL) ActK1->Effect = PE1->next;
    else PE2->next = PE1->next;
    FreeTokenList(PE1->Pred);  free(PE1);
  }

  return TRUE;
}

void GetCEffectListOfActions(PredKnowledge *Pd)
{
  ActKnowledge *ActK, *ActK1;
  TypedList    *Pt1;
  ParaOfAct    *APara;
  PENode       *PE1, *PE2;
  int          i, j, Num, *Pt;

  APara = (ParaOfAct *) calloc(Pd->NumAct, sizeof(ParaOfAct));

  ActK = Pd->Act;
  for (j=0,ActK1=ActK; ActK1 != NULL; j++,ActK1=ActK1->next) {
    APara[j].Num = Num = NumParaOfAct(ActK1->ActNo);
    APara[j].Para = (int *) calloc(Num, sizeof(int));

    Pt = APara[j].Para;   Pt1 = ActK->Para;
    for (i = 0; i < Num; i++,Pt++,Pt1++)
      if (j == 0) *Pt = Pt1->VList.ParaIdx;
      else *Pt = (IsExtraPara(Pt1->VList.ParaIdx) ? NOFOUND : Pt1->VList.ParaIdx);
  }

//PrintPredication(1, Pd);  fprintf(Output, "\n");
  PE1 = ActK->Effect;
  ActK->Effect = NULL;  Pd->CEffect = NULL;
  while (PE1 != NULL) {
    PE2 = PE1;
    PE1 = PE1->next;
    if (CheckOneEffect(APara, PE2, ActK->next)) {
       PE2->next = Pd->CEffect;
       Pd->CEffect = PE2;
       ChangeInfoOfKTreeByCEffect(PE2, APara, Pd);
    }
    else {
           PE2->next = ActK->Effect;
           ActK->Effect = PE2;
    }
  }
//PrintPredication(1, Pd);  fprintf(Output, "\n");

  for (j = 0; j < Pd->NumAct; j++) free(APara[j].Para);
  free(APara);

#ifdef MINIEFFECT
  if (Pd->NumAct > 1) DeleteActionWithMinimumEffect(Pd);
#endif

  Num = NumParaOfPred(Pd->PredNo) + Pd->NumEP;
  j = 0;   Pt1 = Pd->Para;
  for (i = 0; i < Num; i++,Pt1++)
    if (Pt1->VList.NumValue > 0) Pt1->VList.ParaIdx = Pt1->VList.List->Idx;
    else Pt1->VList.ParaIdx = j++;
}

void ChangeInfoOfKTreeByCPC(PredKnowledge *PC, ParaOfAct *APara, PredKnowledge *Pd)
{
  ActKnowledge *ActK, *ActK1;
  TypedList    *Para, *Pt2, *Pt3;
  int          i, j, i1, j1, Num, AllNum;

  AllNum = NumParaOfPred(Pd->PredNo) + Pd->NumEP;

  ActK = Pd->Act;
  Para = PC->Para;
  Num = NumParaOfPred(PC->PredNo);
  for (i = 0; i < Num; i++,Para++) {
    j = Para->VList.ParaIdx;
    if (IsConstant(j)) continue;

    if (!IsExtraPara(APara[0].Para[j])) {
       Para->VList.ParaIdx = APara[0].Para[j];
       continue;
    }

    for (i1=1,ActK1=ActK->next; ActK1 != NULL; i1++,ActK1=ActK1->next) {
      Pt2 = ActK1->Para;
      for (j1 = 0; j1 < APara[i1].Num; j1++,Pt2++)
        if (APara[i1].Para[j1] == APara[0].Para[j]) Pt2->VList.ParaIdx = AllNum;
    }

    APara[0].Para[j] = AllNum;

    Pt2 = ActK->Para + j;

    Pt2->VList.ParaIdx = AllNum;
    Para->VList.ParaIdx = AllNum++;

    Pd->NumEP++;
    Pd->Para = (TypedList *) realloc(Pd->Para, (AllNum)*sizeof(TypedList));

    Pt3 = Pd->Para + (AllNum-1);

    Pt3->VList.ParaIdx = AllNum-1;
    strcpy(Pt3->VList.Name, Pt2->VList.Name);
    Pt3->Type = CopyListOfType(Pt2->Type);

    Pt3->VList.List = NULL;
    CopyValueList(&(Pt3->VList), &(Pt2->VList));
  }
}

void GetCPCOfActions(PredKnowledge *Pd)
{
  PredKnowledge *PC, *PC1;
  ActKnowledge  *ActK, *ActK1;
  ParaOfAct     *APara;
  TypedList     *Pt;
  int           i, j, Num;

//PrintPredication(1, Pd);  fprintf(Output, "\n");
  APara = (ParaOfAct *) calloc(Pd->NumAct, sizeof(ParaOfAct));

  ActK = Pd->Act;
  for (j=0,ActK1 = ActK; ActK1 != NULL; j++,ActK1=ActK1->next) {
    APara[j].Num = Num = NumParaOfAct(ActK1->ActNo);
    APara[j].Para = (int *) calloc(Num, sizeof(int));
  }

  FreePCList(Pd->CPC);  // Free Common PC

  Pd->CPC = NULL;
  for (PC = ActK->PC; PC != NULL; PC = PC->next) {
    // ignore "=" and (not Pd) in PC
    if (IsEqual(PC->PredNo) || EqualNoPredAndPC(Pd, ActK->Para, PC)) continue;

    Pt = ActK->Para;
    for (i = 0; i < APara[0].Num; i++,Pt++) APara[0].Para[i] = Pt->VList.ParaIdx;

    for (j=1,ActK1=ActK->next; ActK1 != NULL; j++,ActK1=ActK1->next) {
      Pt = ActK1->Para;
      for (i = 0; i < APara[j].Num; i++,Pt++) {
        Num = Pt->VList.ParaIdx;
        APara[j].Para[i] = (IsExtraPara(Num) ? NOFOUND : Num);
      }

      if (PCInAction(APara[0].Para, PC, APara+j, ActK1) == NULL) break;
    }

    if (ActK1 != NULL) continue;

    PC->Character |= COMMON;
    for (j=1,ActK1=ActK->next; ActK1 != NULL; j++,ActK1=ActK1->next) {
      PC1 = PCInAction(APara[0].Para, PC, APara+j, ActK1);
      PC1->Character |= COMMON;
    }

    PC1 = (PredKnowledge *) calloc(1, sizeof(PredKnowledge));
    PC1->Para = CopyTypedArray(NumParaOfPred(PC->PredNo), PC->Para);
    PC1->PredNo = PC->PredNo;
    PC1->Type = PC->Type;
    PC1->Level = 2;
    PC1->NumNonValue = PC->NumNonValue;

    PC1->next = Pd->CPC;
    Pd->CPC = PC1;

    ChangeInfoOfKTreeByCPC(PC1, APara, Pd);
  }
//PrintPredication(1, Pd);  fprintf(Output, "\n");

  for (j = 0; j < Pd->NumAct; j++) free(APara[j].Para);
  free(APara);

  if (Pd->NumAct > 1) { // Set Character PC of Action
     Num = 0;
     for (PC = Pd->CPC; PC != NULL; PC = PC->next)
       if (!IsEqual(PC->PredNo)) Num++;

     if (Pd->Type == NOT) Num++;

     for (ActK = Pd->Act; ActK != NULL; ActK = ActK->next)
       if (NumPCOfAct(ActK->ActNo) - Num != 1) break;

     if (ActK == NULL) {
        Pd->Character |= CHARACTER;
        for (ActK = Pd->Act; ActK != NULL; ActK = ActK->next)
          for (PC = ActK->PC; PC != NULL; PC = PC->next)
            if (!IsEqual(PC->PredNo) && !IsType(PC->Character, COMMON) &&
                !EqualNoPredAndPC(Pd, ActK->Para, PC)) {
               PC->Character |= CHARACTER;
               break;
            }
     }
  }
//PrintPredication(1, Pd);  fprintf(Output, "\n");
}

PredKnowledge *GetOnePredKnowledge(TypeOfNode Type, TokenList *Pt, TypedList *APara)
{
  PredKnowledge *Pd;
  TypedList     *Para;
  TokenList     *Pt1;
  PredList	*Pt2;
  PKTree        *Pk, *Pk1;
  int           j, Idx1, Idx2;

  Pk1 = (Type==ATOM ? PK : nPK) + Pt->VList.ParaIdx;

  for (Pk = Pk1->next; Pk != NULL; Pk1=Pk,Pk=Pk->next) {
    Para = Pk->Pred->Para;
    for (Pt1 = Pt->next; Pt1 != NULL; Para++,Pt1=Pt1->next) {
      Idx1 = Para->VList.ParaIdx;
      Idx2 = Pt1->VList.ParaIdx;
      if (IsConstant(Idx1) || IsConstant(Idx2)) {
         if (Idx1 != Idx2) break;
      }
      else if (Typing && !IsSame(Para->Type->Name, (APara+Idx2)->Type->Name))
              break;
    }

    if (Pt1 == NULL) return Pk->Pred;
  }

  Pk = (PKTree *) calloc(1, sizeof(PKTree));

  Pd = (PredKnowledge *) calloc(1, sizeof(PredKnowledge));
  Pd->Type = Type;
  Pd->Acts = Pd->Height = 1;
  Pd->PredNo = Pt->VList.ParaIdx;

  Pt2 = Predication + Pd->PredNo;
  Pd->Para = Para = CopyTypedArray(Pt2->NumPara, Pt2->Para);
  for (j=0,Pt=Pt->next; Pt != NULL; j++,Para++,Pt=Pt->next) {
    if (Pt->VList.NumValue > 0) {
       CopyValueList(&(Para->VList), &(Pt->VList));
       Para->VList.ParaIdx = Pt->VList.ParaIdx;
    }
    else {
           strcpy(Para->Type->Name, (APara+Pt->VList.ParaIdx)->Type->Name);
           Para->VList.ParaIdx = j;
    }
  }

  Pk->Pred = Pd;  Pk1->next = Pk;

  return Pd;
}

#ifdef NEWMOTHED
// Insert Static Predication
Bool PCInPCOfAction(Bool Delete, ActKnowledge *ActK, PredKnowledge *CPC)
{
  PredKnowledge *PC, *PC1;
  TypedList     *Para1, *Para2;
  int           i, Num;

  Num = NumParaOfPred(CPC->PredNo);

  PC1 = NULL;
  for (PC = ActK->PC; PC != NULL; PC1=PC,PC=PC->next)
    if (PC->Type==CPC->Type && PC->PredNo==CPC->PredNo) {
       Para1 = PC->Para;
       Para2 = CPC->Para;
       for (i = 0; i < Num; i++,Para1++,Para2++)
         if (Para1->VList.ParaIdx != Para2->VList.ParaIdx) break;

       if (i < Num) continue;

       if (Delete) {
          if (PC1 == NULL) ActK->PC = PC->next;
          else PC1->next = PC->next;

          FreeTypedArray(Num, PC->Para);
          free(PC);
       }

       return TRUE;
    }

  return FALSE;
}

Bool InsertStaticCPCIntoAction(ActKnowledge *ActK, PredKnowledge *Pd, PredKnowledge *CPC)
{
  PredKnowledge *PC, *PC1;
  TypeOfNode    Type;
  TypedList     *Para;
  int           i, k, PIdx1, PIdx2, PdNo, NumPara;

  Type = Pd->Type;    PdNo = Pd->PredNo;

  for (PC = ActK->PC; PC != NULL; PC = PC->next)
    if (PC->Type==Type && PC->PredNo==PdNo) {
       k = NumParaOfPred(PdNo);
       for (i = 0; i < k; i++) {
         PIdx1 = (PC->Para+i)->VList.ParaIdx;
         PIdx2 = (Pd->Para+i)->VList.ParaIdx;
         if ((IsConstant(PIdx1) || IsConstant(PIdx2)) && PIdx1 != PIdx2) break;
       }

       if (i >= k) break;
    }

  if (PC == NULL) return FALSE;

  NumPara = NumParaOfPred(CPC->PredNo);

  PC1 = (PredKnowledge *) calloc(1, sizeof(PredKnowledge));
  PC1->Type = CPC->Type;
  PC1->PredNo = CPC->PredNo;
  PC1->Level = 2;
  PC1->Fact = TRUE;
  PC1->Para = CopyTypedArray(NumPara, CPC->Para);

  Para = PC1->Para;
  for (i = 0; i < NumPara; i++,Para++) {
    k = Para->VList.ParaIdx;
    if (!IsConstant(k)) {
       Para->VList.ParaIdx = (PC->Para+k)->VList.ParaIdx;
       strcpy(Para->VList.Name, (PC->Para+k)->VList.Name);
    }
  }

  if (PCInPCOfAction(FALSE, ActK, PC1)) {
     FreeTypedArray(NumPara, PC1->Para);
     free(PC1);
  }
  else {
         PC1->next = PC->next;
         PC->next = PC1;
  }

  return TRUE;
}

void InsertStaticCPC(PredKnowledge *Pd, PredKnowledge *CPC)
{
  ActKnowledge *ActK;
  TypedList    *Para;
  TypeOfNode   Type;
  PKTree       *Pk1, *Pk2;
  Bool         Insert;
  int          i, j, k, Num;

//PrintPredication(12, CPC); fprintf(Output, "\n");
//PrintPredication(12, Pd); fprintf(Output, "\n");

  Num = NumParaOfPred(Pd->PredNo);
  k = NumParaOfPred(CPC->PredNo);

  Para = CPC->Para;
  for (j = 0; j < k; j++,Para++)
    if (!IsConstant(Para->VList.ParaIdx) && Para->VList.ParaIdx >= Num) break;

  if (j < k) return;

  Type = Pd->Type;
  for (i=0,Pk1=PK; i < NumPred; i++,Pk1++)
    if (Type==NOT || i != Pd->PredNo)
       for (Pk2 = Pk1->next; Pk2 != NULL; Pk2 = Pk2->next) {
         Insert = FALSE;
         for (ActK = Pk2->Pred->Act; ActK != NULL; ActK = ActK->next)
           Insert = InsertStaticCPCIntoAction(ActK, Pd, CPC) || Insert;

         if (Insert) GetCPCOfActions(Pk2->Pred);
       }

  for (i=0,Pk1=nPK; i < NumPred; i++,Pk1++)
    if (Type!=NOT || i != Pd->PredNo)
       for (Pk2 = Pk1->next; Pk2 != NULL; Pk2 = Pk2->next) {
         Insert = FALSE;
         for (ActK = Pk2->Pred->Act; ActK != NULL; ActK = ActK->next)
           Insert = InsertStaticCPCIntoAction(ActK, Pd, CPC) || Insert;

         if (Insert) GetCPCOfActions(Pk2->Pred);
       }
}

void InsertStaticCPCIntoAction2(ActKnowledge *ActK, PKTree *Pk, PredKnowledge *CPC)
{
  PredKnowledge *PC, *PC1, *PkPC, *PkPd;
  TypedList     *Para;
  int           i, k, PIdx1, PIdx2, PCNo, PdNo, NumPara;
  int           *ParaIdx;

  PkPC = Pk->PC;    PCNo = PkPC->PredNo;
  PkPd = Pk->Pred;  PdNo = PkPd->PredNo;

  NumPara = NumParaOfPred(PdNo) + PkPd->NumEP;

  ParaIdx = (int *) calloc(NumPara, sizeof(int));

  for (i = 0; i < NumPara; i++) ParaIdx[i] = NOFOUND;

  for (PC = ActK->PC; PC != NULL; PC = PC->next) {
    if (PC->Type!=PkPC->Type || PC->PredNo!=PCNo) continue;

    k = NumParaOfPred(PCNo);
    for (i = 0; i < k; i++) {
      PIdx1 = (PC->Para+i)->VList.ParaIdx;
      PIdx2 = (PkPC->Para+i)->VList.ParaIdx;
      if ((IsConstant(PIdx1) || IsConstant(PIdx2)) && PIdx1 != PIdx2) break;

      if (ParaIdx[PIdx2] == NOFOUND) ParaIdx[PIdx2] = PIdx1;
      else if (ParaIdx[PIdx2] != PIdx1) break;
    }

    if (i < k) continue;

    for (PC1 = ActK->PC; PC1 != NULL; PC1 = PC1->next) {
      if (PC1->Type==PkPd->Type && PC1->PredNo==PdNo) {
         k = NumParaOfPred(PdNo);
         for (i = 0; i < k; i++) {
           PIdx1 = (PC1->Para+i)->VList.ParaIdx;
           PIdx2 = (PkPd->Para+i)->VList.ParaIdx;
           if ((IsConstant(PIdx1) || IsConstant(PIdx2)) && PIdx1 != PIdx2) break;

           if (ParaIdx[PIdx2] == NOFOUND) ParaIdx[PIdx2] = PIdx1;
           else if (ParaIdx[PIdx2] != PIdx1) break;
         }

         if (i >= k) break;
      }
    }

    if (PC1 != NULL) break;
  }

  if (PC == NULL) { free(ParaIdx);  return; }

  NumPara = NumParaOfPred(CPC->PredNo);

  PC1 = (PredKnowledge *) calloc(1, sizeof(PredKnowledge));
  PC1->Type = CPC->Type;
  PC1->PredNo = CPC->PredNo;
  PC1->Level = 2;
  PC1->Fact = TRUE;
  PC1->Para = CopyTypedArray(NumPara, CPC->Para);

  Para = PC1->Para;
  for (i = 0; i < NumPara; i++,Para++) {
    k = Para->VList.ParaIdx;
    if (!IsConstant(k)) {
       k = ParaIdx[k];
       Para->VList.ParaIdx = k;
       strcpy(Para->VList.Name, (ActK->Para+k)->VList.Name);
    }
  }

  if (PCInPCOfAction(FALSE, ActK, PC1)) {
     FreeTypedArray(NumPara, PC1->Para);
     free(PC1);
  }
  else {
         PC1->next = ActK->PC;
         ActK->PC = PC1;
  }

  free(ParaIdx);
}

void InsertStaticCPC2(PKTree *Pk, PredKnowledge *CPC)
{
  PredKnowledge *PC, *Pd;
  ActKnowledge  *ActK;
  TypedList     *Para;
  PKTree        *Pk1, *Pk2, *Pk3;
  int           i, j, k, Num;

//PrintPredication(12, CPC); fprintf(Output, "\n");

  PC = Pk->PC;
  Pd = Pk->Pred;
  Num = NumParaOfPred(Pd->PredNo);
  k = NumParaOfPred(CPC->PredNo);

  Para = CPC->Para;
  for (j = 0; j < k; j++,Para++)
    if (!IsConstant(Para->VList.ParaIdx) && Para->VList.ParaIdx >= Num) break;

  if (j < k) return;

  Pk1 = PK;   Pk2 = nPK;
  for (i = 0; i < NumPred; i++,Pk1++,Pk2++)
    if (i != PC->PredNo) {
       for (Pk3 = Pk1->next; Pk3 != NULL; Pk3 = Pk3->next)
         for (ActK = Pk3->Pred->Act; ActK != NULL; ActK = ActK->next)
           InsertStaticCPCIntoAction2(ActK, Pk, CPC);

       for (Pk3 = Pk2->next; Pk3 != NULL; Pk3 = Pk3->next)
         for (ActK = Pk3->Pred->Act; ActK != NULL; ActK = ActK->next)
           InsertStaticCPCIntoAction2(ActK, Pk, CPC);
    }
}

PredKnowledge *GetStaticPC(ActKnowledge *ActK, int Num, PredKnowledge *PC)
{
  PredKnowledge *PC1, *PC2;
  TypedList     *Para1;
  int           i, j, Num1;

#ifdef DELETE_STATIC_CPC
  PC2 = NULL;
  for (PC1 = ActK->PC; PC1 != NULL; PC2=PC1,PC1=PC1->next) {
#else
  for (PC1 = ActK->PC; PC1 != NULL; PC1 = PC1->next) {
#endif
    if (IsEqual(PC1->PredNo) || !IsClass(PC1->PredNo, STATIC)) continue;

    Num1 = NumParaOfPred(PC1->PredNo);

    Para1 = PC1->Para;
    for (i = 0; i < Num1; i++,Para1++) {
      j = Para1->VList.ParaIdx;
      if (!IsConstant(j)) {
         j = (ActK->Para+j)->VList.ParaIdx;
         if (j >= Num) break;
      }

      if (PC != NULL && (PC->Para+i)->VList.ParaIdx != j) break;
    }

    if (i < Num1) continue;

#ifdef DELETE_STATIC_CPC
    if (PC2 == NULL) ActK->PC = PC1->next;
    else PC2->next = PC1->next;
#else
    PC2 = (PredKnowledge *) calloc(1, sizeof(PredKnowledge));
    PC2->Type = PC1->Type;
    PC2->PredNo = PC1->PredNo;
    PC2->Para = CopyTypedArray(Num1, PC1->Para);
    PC1 = PC2;
#endif

    Para1 = PC1->Para;
    for (i = 0; i < Num1; i++,Para1++) {
      j = Para1->VList.ParaIdx;
      if (IsConstant(j)) Para1->VList.ParaIdx = j;
      else Para1->VList.ParaIdx = (ActK->Para+j)->VList.ParaIdx;
    }

    return PC1;
  }

  return NULL;
}

void PartitionActionTree(PKTree *Pk, ActKnowledge *ActK, PredKnowledge *PC)
{
  PredKnowledge *PC1, *Pd, *Pd1;
  ActKnowledge  *ActK1, *ActK3;
  PKTree        *Pk1;
  int           Num;

  Pd = Pk->next->Pred;

  Pd1 = (PredKnowledge *) calloc(1, sizeof(PredKnowledge));

  Pd1->Type = Pd->Type;
  Pd1->Acts = Pd1->Height = 1;
  Pd1->PredNo = Pd->PredNo;
  Pd1->NumEP = Pd->NumEP;
  Pd1->Para = CopyTypedArray(NumParaOfPred(Pd->PredNo)+Pd->NumEP, Pd->Para);

  if (ActK == NULL) { ActK3 = NULL;  ActK = Pd->Act; }
  else { ActK3 = ActK;  ActK = ActK->next; }

  ActK1 = Pd1->Act = ActK;

  // Clear Character PC Of Action
  Num = 0;
  for (PC1 = ActK->PC; PC1 != NULL; Num++,PC1=PC1->next)
    PC1->Character = NONE;

  NumPCOfAct(ActK->ActNo) = Num;

  Pd->NumAct--;    Pd1->NumAct = 1;

  ActK = ActK->next;
  while (ActK != NULL) {
#ifdef DELETE_STATIC_CPC
    if (PCInPCOfAction(TRUE, ActK, PC)) {
#else
    if (PCInPCOfAction(FALSE, ActK, PC)) {
#endif
       // Clear Character PC Of Action
       Num = 0;
       for (PC1 = ActK->PC; PC1 != NULL; Num++,PC1=PC1->next)
         PC1->Character = NONE;

       NumPCOfAct(ActK->ActNo) = Num;

       Pd->NumAct--;
       Pd1->NumAct++;
       ActK1->next = ActK;
       ActK1 = ActK;
    }
    else {
           if (ActK3 == NULL) Pd->Act = ActK;
           else ActK3->next = ActK;
           ActK3 = ActK;
    }

    ActK = ActK->next;
  }

  ActK1->next = NULL;
  if (ActK3 == NULL) Pd->Act = NULL;
  else ActK3->next = NULL;

  GetCPCOfActions(Pd1);

  Pk1 = (PKTree *) calloc(1, sizeof(PKTree));
  Pk1->PC = PC;
  Pk1->Pred = Pd1;

  Pk1->next = Pk->next;  Pk->next = Pk1;
}

#ifdef DELETE_STATIC_CPC
void DeleteCPCFromPKTree(PredKnowledge *Pd, PredKnowledge *CPC)
{
  PredKnowledge *PC, *PC1;
  ActKnowledge  *ActK;
  TypedList     *Para1, *Para2;
  int           i, j, Num;

  Num = PREDNUMPARA(CPC->PredNo);
  for (ActK = Pd->Act; ActK != NULL; ActK = ActK->next) {
    PC1 = NULL;
    for (PC = ActK->PC; PC != NULL; PC1=PC,PC=PC->next)
      if (PC->Type==CPC->Type && PC->PredNo==CPC->PredNo) {
         Para1 = PC->Para;
         Para2 = CPC->Para;
         for (i = 0; i < Num; i++,Para1++,Para2++) {
           j = Para1->VList.ParaIdx;
           if (!CONSTANT(j)) j = (ActK->Para+j)->VList.ParaIdx;
           if (j != Para2->VList.ParaIdx) break;
         }

         if (i < Num) continue;

         if (PC1 == NULL) ActK->PC = PC->next;
         else PC1->next = PC->next;

         FreeTypedArray(Num, PC->Para);
         free(PC);
      }
  }
}
#endif

PKTree *CopyPKTree(PKTree *PK)
{
  PredKnowledge *Pd, *Pd1, *PC, *PC1, *PC2;
  ActKnowledge  *ActK, *ActK1, *ActK2;
  PKTree        *Pk;

  Pd = PK->Pred;

  Pk = (PKTree *) calloc(1, sizeof(PKTree));
  Pk->Pred = Pd1 = CopyOnePC(Pd);

  PC1 = NULL;
  for (PC = Pd->CPC; PC != NULL; PC = PC->next) {
    PC2 = CopyOnePC(PC);
    if (PC1 == NULL) Pd1->CPC = PC2;
    else PC1->next = PC2;
    PC1 = PC2;
  }

  ActK1 = NULL;
  for (ActK = Pd->Act; ActK != NULL; ActK = ActK->next) {
    ActK2 = CopyActKnowledge(ActK, Pd1);
    if (ActK1 == NULL) Pd1->Act = ActK2;
    else ActK1->next = ActK2;
    ActK1 = ActK2;
  }
//PrintPKTree(Pk);

  return Pk;
}

PKTree *SplitActionTree(PKTree *Pk, Bool *Change)
{
  PredKnowledge *Pd, *PC, *PC1, *PC2;
  ActKnowledge  *ActK, *ActK1;
  PKTree        *Pk1;
  int           Num;
#ifndef MULTIPCS
  TypedList     *Para;
  int           i, Num1;
#endif

  Pk1 = Pk->next;   Pd = Pk1->Pred;

  if (Pd->CPC != NULL) {
#ifndef MULTIPCS
     Num1 = NumParaOfPred(Pd->PredNo);
#endif
     PC2 = NULL;
     for (PC = Pd->CPC; PC != NULL; PC = PC->next) {
       if (PC->Type != ATOM || !IsClass(PC->PredNo, STATIC)) continue;

       Num = NumParaOfPred(PC->PredNo);
#ifndef MULTIPCS
       Para = PC->Para;
       for (i = 0; i < Num; i++,Para++)
         if (Para->VList.ParaIdx >= Num1) break;

       if (i < Num) continue;
#endif

       PC1 = (PredKnowledge *) calloc(1, sizeof(PredKnowledge));
       PC1->Type = PC->Type;
       PC1->PredNo = PC->PredNo;

       PC1->Para = CopyTypedArray(Num, PC->Para);

       if (PC2 == NULL) Pk1->PC = PC1;
       else PC2->next = PC1;

       PC2 = PC1;
#ifndef MULTIPCS
       break;
#endif
     }

     if (PC2 != NULL) return Pk1;
  }

//PrintPredication(12, Pd); fprintf(Output, "\n");
  Num = NumParaOfPred(Pd->PredNo) + Pd->NumEP;
  PC = NULL;
  ActK = NULL;
  ActK1 = Pd->Act;
  while (ActK1 != NULL) {
    PC1 = GetStaticPC(ActK1, Num, PC);
    if (PC1 == NULL) ActK=ActK1, ActK1=ActK1->next;
    else {
           *Change = TRUE;
           PartitionActionTree(Pk, ActK, PC1);

           if (ActK == NULL) ActK1 = Pd->Act;
           else ActK1 = ActK->next;

           Pk = Pk->next;

           if (PC == NULL) PC = PC1;
    }
  }

  if (Pd->Act == NULL) {
     Pk->next = Pk1->next;
     FreePKTree(Pk1);
     return Pk;
  }

  return Pk1;
}
#endif

void handleOneEffect(int Idx, PENode *PE, int Index)
{
  PredKnowledge *Pd, *PC1, *PC2;
  ActKnowledge  *ActK, *ActK1, *ActK2;
  ActionList    *Act;
  TypedList     *P1, *Para;
  TokenList     *Pt1;
  PENode        *PE1;
  int           j, k, Num;

  Pt1 = PE->Pred;

  if (IsEqual(Pt1->VList.ParaIdx)) return;

  Act = (Action+Idx)->next;
  Pd = GetOnePredKnowledge(PE->Type, Pt1, Act->Para);

  ActK = (ActKnowledge *) calloc(1, sizeof(ActKnowledge));
  ActK->ActNo = Idx;
  ActK->Type = Act->Type;

  // action parameters' default value
  ActK->Para = Para = CopyTypedArray(Act->NumPara, Act->Para);
  for (j = 0; j < Act->NumPara; j++,Para++) {
    sprintf(Para->VList.Name, "%s%d", Para->VList.Name, j);
    Para->VList.ParaIdx = EXTRAPARA + j;
  }

  Num = NumParaOfPred(Pd->PredNo);
  P1 = Pd->Para;
  for (j = 0; j < Num; j++,P1++) {
    Pt1 = Pt1->next;
    k = Pt1->VList.ParaIdx;
    if (!IsConstant(k)) {
       Para = ActK->Para + k;
       strcpy(Para->VList.Name, P1->VList.Name);
       Para->VList.ParaIdx = P1->VList.ParaIdx;
       Para->VList.NumValue = P1->VList.NumValue;
    }
  }

  ActK->Parent = Pd;

  ActK->PC = NULL;    // Copy PC List of Action
  for (PE1 = Act->PC; PE1 != NULL; PE1 = PE1->next) {
    PC2 = CopyOnePCOfAction(ActK->Para, PE1);

    PC2->Level = 2;
    PC2->Parent = ActK->Parent;

    if (ActK->PC == NULL) ActK->PC = PC2;
    else PC1->next = PC2;
    PC1 = PC2;
  }

  ActK->Effect = CopyEffectOfAction(Act->Effect);
#ifdef WHEN_CLAUSE
  CopyCondEffectOfAction(ActK, Act->CondEffect, Index);
#endif

  InstanceEffectOfAction(ActK);

//PrintPredication(2, Pd);    fprintf(Output, "\n");
//PrintActKnowledge(1, ActK); fprintf(Output, "\n");
  ActK1 = Pd->Act;
  ActK2 = NULL;    Num = Act->NumPC;
  while (ActK1!=NULL && NumPCOfAct(ActK1->ActNo)<=Num)
    ActK2 = ActK1, ActK1 = ActK1->next;

  if (Pd->Act == NULL) { Pd->Act = ActK; Pd->NumAct++; }
  else if (ActK2 == NULL) InsertActKnowledge(BEFORE, Pd->Act, ActK);
       else InsertActKnowledge(AFTER, ActK2, ActK);

//PrintPredication(2, Pd); fprintf(Output, "\n");
}

void GetDomainKnowledgeTree()
{
  ActionList *Act;
  PredList   *Pred;
  PKTree     *Pk, *Pk1, *Pk2;
  PENode     *PE, *PE1;
  int        i;
#ifdef WHEN_CLAUSE
  int        k;
#endif
#ifdef NEWMOTHED
  PredKnowledge *Pd;
  PKTree        *Pk3;
  Bool          Change;
#endif

//PrintDomain();
  PK = (PKTree *) calloc(NumPred, sizeof(PKTree));
  nPK = (PKTree *) calloc(NumPred, sizeof(PKTree));

  // Scan Action List to build Knowledge Tree
  for (i = 0; i < NumAct; i++) {
    Act = (Action+i)->next;

    for (PE = Act->Effect; PE != NULL; PE = PE->next)
      handleOneEffect(i, PE, -1);

#ifdef WHEN_CLAUSE
    for (k=0,PE=Act->CondEffect; PE != NULL; k++,PE=PE->next)
      for (PE1 = PE->Effect; PE1 != NULL; PE1 = PE1->next)
        handleOneEffect(i, PE1, k);
#endif
  }
//PrintKnowledgeTree();

  // set attribute of pred and
  // get common pre-condition infomatioin of PK tree
  Pred = Predication;
  for (i=0,Pk1=PK,Pk2=nPK; i < NumPred; i++,Pk1++,Pk2++,Pred++) {
    if (Pk1->next != NULL) Pred->Class |= ASCENDING;
    if (Pk2->next != NULL) Pred->Class |= DESCENDING;

    for (Pk = Pk1->next; Pk != NULL; Pk = Pk->next)
      if (Pk->Pred->Act != NULL) GetCPCOfActions(Pk->Pred);

    for (Pk = Pk2->next; Pk != NULL; Pk = Pk->next)
      if (Pk->Pred->Act != NULL) GetCPCOfActions(Pk->Pred);
  }

#ifdef NEWMOTHED
  // insert common static precondition
  for (i=0,Pk1=PK,Pk2=nPK; i < NumPred; i++,Pk1++,Pk2++) {
    for (Pk = Pk1->next; Pk != NULL; Pk = Pk->next)
      for (Pd = Pk->Pred->CPC; Pd != NULL; Pd = Pd->next)
        if (!IsEqual(Pd->PredNo) && IsClass(Pd->PredNo, STATIC))
           InsertStaticCPC(Pk->Pred, Pd);

    for (Pk = Pk2->next; Pk != NULL; Pk = Pk->next)
      for (Pd = Pk->Pred->CPC; Pd != NULL; Pd = Pd->next)
        if (!IsEqual(Pd->PredNo) && IsClass(Pd->PredNo, STATIC))
           InsertStaticCPC(Pk->Pred, Pd);
  }

//PrintKnowledgeTree();
  Change = FALSE;
  for (i=0,Pk1=PK,Pk2=nPK; i < NumPred; i++,Pk1++,Pk2++) {
    Pk3 = Pk1;
    while (Pk3->next != NULL) Pk3 = SplitActionTree(Pk3, &Change);

    Pk3 = Pk2;
    while (Pk3->next != NULL) Pk3 = SplitActionTree(Pk3, &Change);
  }
//PrintKnowledgeTree();

  if (Change) {
     for (i=0,Pk1=PK,Pk2=nPK; i < NumPred; i++,Pk1++,Pk2++) {
       for (Pk = Pk1->next; Pk != NULL; Pk = Pk->next)
         for (Pd = Pk->Pred->CPC; Pd != NULL; Pd = Pd->next)
           if (!IsEqual(Pd->PredNo) && IsClass(Pd->PredNo, STATIC))
              InsertStaticCPC2(Pk, Pd);

       for (Pk = Pk2->next; Pk != NULL; Pk = Pk->next)
         for (Pd = Pk->Pred->CPC; Pd != NULL; Pd = Pd->next)
           if (!IsEqual(Pd->PredNo) && IsClass(Pd->PredNo, STATIC))
              InsertStaticCPC2(Pk, Pd);
     }
  }
#endif

//PrintKnowledgeTree();
  // get common effects of PK tree
  for (i=0,Pk1=PK,Pk2=nPK; i < NumPred; i++,Pk1++,Pk2++) {
    for (Pk = Pk1->next; Pk != NULL; Pk = Pk->next)
      if (Pk->Pred->Act != NULL) GetCEffectListOfActions(Pk->Pred);

    for (Pk = Pk2->next; Pk != NULL; Pk = Pk->next)
      if (Pk->Pred->Act != NULL) GetCEffectListOfActions(Pk->Pred);
  }
//PrintDomain();  PrintKnowledgeTree();
}
